package com.kakarote.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kakarote.admin.common.AdminCodeEnum;
import com.kakarote.admin.common.AdminConfigLogEnum;
import com.kakarote.admin.common.AdminModuleEnum;
import com.kakarote.admin.entity.BO.*;
import com.kakarote.admin.entity.PO.*;
import com.kakarote.admin.entity.VO.ModuleSettingVO;
import com.kakarote.admin.mapper.AdminConfigMapper;
import com.kakarote.admin.service.*;
import com.kakarote.common.log.entity.OperationLog;
import com.kakarote.core.common.Const;
import com.kakarote.core.common.cache.AdminCacheKey;
import com.kakarote.core.common.cache.CrmCacheKey;
import com.kakarote.core.common.enums.SystemCodeEnum;
import com.kakarote.core.entity.BasePage;
import com.kakarote.core.entity.PageEntity;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.exception.CrmException;
import com.kakarote.core.feign.crm.entity.SimpleCrmEntity;
import com.kakarote.core.feign.oa.OaService;
import com.kakarote.core.redis.Redis;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.BaseUtil;
import com.kakarote.core.utils.UserUtil;
import com.kakarote.hrm.feign.service.HrmService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.kakarote.admin.common.AdminModuleEnum.*;

/**
 * <p>
 * 客户规则 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-04-27
 */
@Service
@Slf4j
public class AdminConfigServiceImpl extends BaseServiceImpl<AdminConfigMapper, AdminConfig> implements IAdminConfigService {

    private static final String LOG_CONFIG_NAME = "logWelcomeSpeech";

    @Autowired
    private IAdminApplyService adminApplyService;

    @Autowired
    private IAdminRoleService adminRoleService;

    @Autowired
    private IAdminUserService adminUserService;

    @Autowired
    private IAdminAttentionService adminAttentionService;

    @Autowired
    private IAdminUserRoleService adminUserRoleService;

    @Autowired
    private OaService oaService;
    @Autowired
    private HrmService hrmService;


    @Autowired
    private IAdminMessageService adminMessageService;

    @Autowired
    private IAdminConfigService adminConfigService;



    /**
     * 通过name查询系统配置
     *
     * @param names names
     * @return adminConfig
     */
    @Override
    public List<AdminConfig> queryConfigListByName(Object... names) {
        return query().in("name", names).list();
    }

    /**
     * 设置企业配置
     *
     * @param adminConfig config
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OperationLog setAdminConfig(AdminCompanyBO adminConfig) {
        List<AdminConfig> list = adminConfigService.lambdaQuery().in(AdminConfig::getName, "companyName", "companyLogo", "companyLoginLogo").list();
        OperationLog operationLog = new OperationLog();
        operationLog.setOperationObject("企业首页");

        StringBuilder updateInfo = new StringBuilder("编辑了");
        boolean isUpdate = false;
        for (AdminConfig config : list) {
            switch (config.getName()) {
                case "companyName":
                    if (ObjectUtil.notEqual(config.getValue(), adminConfig.getCompanyName())) {
                        updateInfo.append("企业名称;");
                        isUpdate = true;
                    }
                    config.setValue(adminConfig.getCompanyName());
                    break;
                case "companyLogo":
                    if (ObjectUtil.notEqual(config.getValue(), adminConfig.getCompanyLogo())) {
                        updateInfo.append("企业logo;");
                        isUpdate = true;
                    }
                    config.setValue(adminConfig.getCompanyLogo());
                    break;
                case "companyLoginLogo":
                    if (ObjectUtil.notEqual(config.getValue(), adminConfig.getCompanyLoginLogo())) {
                        updateInfo.append("企业登录页logo;");
                        isUpdate = true;
                    }
                    config.setValue(adminConfig.getCompanyLoginLogo());
                    break;
                default:
                    break;
            }
        }
        if (!isUpdate) {
            updateInfo = new StringBuilder("无修改");
        }
        operationLog.setOperationInfo(updateInfo.toString());

        adminConfigService.updateBatchById(list);
        return operationLog;
    }

    @Override
    public OperationLog setAdminConfig(String name, List<AdminConfigBO> list) {
        AdminConfigLogEnum adminConfigLogEnum = AdminConfigLogEnum.valueOf(StrUtil.toUnderlineCase(name).toUpperCase());
        List<AdminConfig> configList = new ArrayList<>();
        list.forEach(adminConfigBO -> {
            AdminConfig config = new AdminConfig();
            config.setName(name);
            config.setValue(adminConfigBO.getValue());
            if(adminConfigBO.getStatus() == null){
                config.setStatus(1);
            }else{
                config.setStatus(adminConfigBO.getStatus());
            }
            config.setDescription(adminConfigLogEnum.getDescription());
            configList.add(config);
        });
        QueryWrapper<AdminConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", name);
        remove(queryWrapper);
        saveBatch(configList, Const.BATCH_SAVE_SIZE);

        OperationLog operationLog = new OperationLog();
        operationLog.setOperationObject(adminConfigLogEnum.getDescription());
        operationLog.setOperationInfo("编辑了" + adminConfigLogEnum.getDescription());
        operationLog.setApply(adminConfigLogEnum.getOperateLogApply());
        operationLog.setApplyObject(adminConfigLogEnum.getOperateLogModule());
        return operationLog;
    }

    /**
     * 查询企业配置
     *
     * @return adminCompanyBO
     */
    @Override
    public AdminCompanyBO queryAdminConfig() {
        UserInfo user = UserUtil.getUser();
        List<AdminConfig> configs = adminConfigService.queryConfigListByName("companyName", "companyLogo", "companyLoginLogo");
        Map<String, String> collect = configs.stream().collect(Collectors.toMap(AdminConfig::getName, entry -> Optional.ofNullable(entry.getValue()).orElse("")));
        AdminCompanyBO companyBO = BeanUtil.toBean(collect, AdminCompanyBO.class);
        return companyBO;
    }

    /**
     * 忽略企业过期提醒
     */
    @Override
    public void ignoreCompanyStatus() {

    }

    /**
     * 查询模块设置
     *
     * @return data
     */
    @Override
    public List<ModuleSettingVO> queryModuleSetting() {
        List<AdminConfig> adminConfigList = queryConfigListByName((Object[]) getValues());
        List<ModuleSettingVO> moduleSettingList = new ArrayList<>();
        adminConfigList.forEach(adminConfig -> {
            ModuleSettingVO moduleSettingVO = new ModuleSettingVO();
            moduleSettingVO.setSettingId(adminConfig.getSettingId());
            moduleSettingVO.setModule(adminConfig.getName());
            moduleSettingVO.setStatus(adminConfig.getStatus());
            //增值应用需要特殊处理
            String adminValue = "3";
            if (Objects.equals(adminValue, adminConfig.getValue())) {
                moduleSettingVO.setApplyStatus(0);
            }
            moduleSettingVO.setType(adminConfig.getValue());
            moduleSettingVO.setName(adminConfig.getDescription());
            //添加语言包key
            Map<String, String> keyMap = new HashMap<>();
            String fieldName = moduleSettingVO.getName();
            if (StrUtil.isNotBlank(fieldName) && fieldName.endsWith("Id")) {
                fieldName = fieldName.substring(0, fieldName.lastIndexOf("Id")).concat("Name");
            }
            if (StrUtil.isNotBlank(fieldName) && fieldName.endsWith("Ids")) {
                fieldName = fieldName.substring(0, fieldName.lastIndexOf("Ids")).concat("Names");
            }
            if (StrUtil.isNotBlank(fieldName)) {
                keyMap.put("name_resourceKey", "application.options" + "." + fieldName);
            }
            moduleSettingVO.setLanguageKeyMap(keyMap);
            moduleSettingList.add(moduleSettingVO);
        });
        return moduleSettingList;
    }

    @Autowired
    private Redis redis;

    /**
     * 设置模块的禁用启用
     *
     * @param adminConfig data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setModuleSetting(AdminConfig adminConfig) {
        String key = "ModuleSetting:";
        AdminConfig config = getById(adminConfig.getSettingId());
        long timeOut = 10L;
        if (redis.setNx(key, timeOut, 1)) {
            //如果是增值应用启用
            String adminValue = "3";
            Optional<AdminApply> applyOptional = adminApplyService.lambdaQuery().eq(AdminApply::getName, config.getName()).oneOpt();
            //已试用过的呼叫中心、工商信息查询不可继续操作启用禁用
            if (applyOptional.isPresent() && Arrays.asList(CALL.getValue(), ENTERPRISE.getValue()).contains(config.getName())) {
                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
            }
            if (Objects.equals(adminValue, config.getValue()) && Objects.equals(1, adminConfig.getStatus()) && !applyOptional.isPresent()) {
                //满足试用
                AdminApply adminApply = AdminApply.builder().id(BaseUtil.getNextId()).name(config.getName()).createTime(LocalDateTime.now()).createUserId(0L).updateTime(LocalDateTime.now()).updateUserId(0L).status(2).endTime(DateUtil.offsetDay(new DateTime(), 7).toLocalDateTime()).build();
                adminApplyService.save(adminApply);
            }
            lambdaUpdate().set(AdminConfig::getStatus, adminConfig.getStatus()).eq(AdminConfig::getSettingId, adminConfig.getSettingId()).update();
            //查询企业用户，将企业用户的权限缓存清除，重新计算
            List<AdminUser> adminUsers = adminUserService.lambdaQuery().select(AdminUser::getUserId).list();
            //清除缓存
            adminRoleService.authInvalidate(adminUsers.stream().map(AdminUser::getUserId).collect(Collectors.toList()));
            redis.del(key);
        } else {
            throw new CrmException(SystemCodeEnum.SYSTEM_BAD_REQUEST);
        }

    }

    /**
     * 查询系统配置
     *
     * @return data
     */
    @Override
    public List<AdminConfigBO> getAdminConfig(String name) {
        List<AdminConfig> adminConfigList = query().select("setting_id", "value", "status").eq("name", name).list();
        return adminConfigList.stream().map(adminConfig -> BeanUtil.copyProperties(adminConfig, AdminConfigBO.class)).collect(Collectors.toList());
    }

    /**
     * 根据名称查询配置信息
     *
     * @param name
     * @return data
     */
    @Override
    public AdminConfig queryConfigByName(String name) {
        return query().in("name", name).one();
    }

    /**
     * 查询呼叫中心设置
     *
     * @return data
     */
    @Override
    public ModuleSettingVO queryCallModuleSetting() {
        AdminConfig adminConfig = queryConfigByName(CALL.getValue());
        ModuleSettingVO moduleSettingVO = new ModuleSettingVO();
        moduleSettingVO.setSettingId(adminConfig.getSettingId());
        moduleSettingVO.setModule(adminConfig.getName());
        moduleSettingVO.setStatus(adminConfig.getStatus());
        moduleSettingVO.setType(adminConfig.getValue());
        moduleSettingVO.setName(adminConfig.getDescription());
        return moduleSettingVO;
    }


    @Override
    public void updateAdminConfig(AdminConfig adminConfig) {
        saveOrUpdate(adminConfig);
    }

    @Override
    public String verifyPassword(AdminInitDataBO adminInitDataBO) {
        Long userId = UserUtil.getUserId();
        AdminUser user = adminUserService.getById(userId);
        String userName = user.getUsername();
        boolean isPass = UserUtil.verify(userName + adminInitDataBO.getPassword(), user.getSalt(), user.getPassword());
        if (isPass) {
            String cacheName = AdminCacheKey.TEMPORARY_ACCESS_CODE_CACHE_KEY + userId;
            String value = String.valueOf(RandomUtil.randomInt(100000, 999999));
            BaseUtil.getRedis().setex(cacheName, 600, value);
            return value;
        }
        throw new CrmException(AdminCodeEnum.ADMIN_PASSWORD_INVALID_ERROR);
    }


    @Override
    public List<OperationLog> moduleInitData(AdminInitDataBO adminInitDataBO) {
        UserInfo userInfo = UserUtil.getUser();
        Long userId = userInfo.getUserId();
        if (!userInfo.isWxUser() && !userInfo.isFlyUser()) {
            String cacheName = AdminCacheKey.TEMPORARY_ACCESS_CODE_CACHE_KEY + userId;
            String temporaryCode = BaseUtil.getRedis().get(cacheName);
            if (StrUtil.isEmpty(temporaryCode)) {
                //超时未操作
                throw new CrmException(AdminCodeEnum.ADMIN_PASSWORD_EXPIRE_ERROR);
            }
            if (!temporaryCode.equals(adminInitDataBO.getTemporaryCode())) {
                throw new CrmException(AdminCodeEnum.ADMIN_PASSWORD_INVALID_ERROR);
            }
        }
        redis.del(CrmCacheKey.CRM_BACKLOG_NUM_CACHE_KEY + userId.toString());
        List<String> modules = adminInitDataBO.getModules();

        if (CollUtil.isNotEmpty(modules)) {
            List<OperationLog> operationLogList = new ArrayList<>();
            for (String module : modules) {
                AdminModuleEnum adminModuleEnum = AdminModuleEnum.parse(module);
                if (adminModuleEnum == null) {
                    continue;
                }
                OperationLog operationLog = new OperationLog();
                operationLog.setOperationInfo("初始化" + adminModuleEnum.getRemark() + "数据");
                operationLog.setOperationObject(adminModuleEnum.getRemark());
                operationLogList.add(operationLog);
                switch (adminModuleEnum) {
                    case TASK_EXAMINE:
                        //oa、work
                        oaService.initOaExamineData();
                        adminMessageService.lambdaUpdate().eq(AdminMessage::getLabel, 1).remove();
                        break;
                    case LOG:
                    case OA:
                        oaService.initOaData();
                        adminMessageService.lambdaUpdate().in(AdminMessage::getLabel, 2, 3).remove();
                        break;
                    case BOOK:
                        if (!UserUtil.isAdmin()) {
                            if (this.verifyInitAuth()) {
                                throw new CrmException(SystemCodeEnum.SYSTEM_NO_AUTH);
                            }
                        }
                        log.info("开始初始化通讯录模块数据！");
                        List<AdminUser> adminUsers = adminUserService.lambdaQuery().select(AdminUser::getUserId)
                                .ne(AdminUser::getUserId, UserUtil.getUserId()).list();
                        if (CollUtil.isNotEmpty(adminUsers)) {
                            List<Long> userIds = adminUsers.stream().map(AdminUser::getUserId).collect(Collectors.toList());
                            adminAttentionService.lambdaUpdate().in(AdminAttention::getBeUserId, userIds).or().in(AdminAttention::getAttentionUserId, userIds)
                                    .remove();
                            adminUserRoleService.lambdaUpdate().in(AdminUserRole::getUserId, userIds)
                                    .remove();
                            adminUserService.removeByIds(userIds);
                        }
                        log.info("通讯录模块数据初始化完成！");
                        break;
                    case CALENDAR:
                        //oa
                        oaService.initCalendarData();
                        adminMessageService.lambdaUpdate().eq(AdminMessage::getLabel, 5).remove();
                        break;
                    case HRM:
                        hrmService.initHrmData();
                        log.info("人力资源模块重置数据完成！");
                        AdminConfig company = adminConfigService.queryConfigByName("companyName");
                        String companyName = Optional.ofNullable(company.getValue()).orElse("全公司");
                        hrmService.initData( UserUtil.getUserId(), companyName, false);
                        log.info("人力资源模块初始化数据完成！");
                        adminMessageService.lambdaUpdate().eq(AdminMessage::getLabel, 8).remove();
                        break;
                    case FINANCE:
                        break;
                    case JXC:
                        break;
                    default:
                        break;
                }
            }
            return operationLogList;
        }
        return null;
    }

    @Override
    public AdminConfig queryConfigByNameAndCompanyId(String name) {
        return query().in("name", name).one();
    }

    @Override
    public AdminConfig queryConfigByNameAndCompanyIdSkip(String name) {
        return getBaseMapper().queryConfigByNameAndCompanyIdSkip(name);
    }


    @Override
    public Integer updateAdminApplyNumberInfo(String name, Integer number) {
        return adminApplyService.updateAdminApplyNumberInfo(name, number);
    }

    @Override
    public List<ModuleSettingVO> queryModuleApply(AdminQueryModuleApplyBO queryBO) {
        List<Long> goodsIds = queryBO.getGoodsIds();
        List<ModuleSettingVO> moduleSettingList = new ArrayList<>();
        if (CollUtil.isEmpty(goodsIds)) {
            return moduleSettingList;
        }

        return moduleSettingList;
    }


    @Override
    public List<OperationLog> setMonetaryUnit(List<MonetaryUnitBO> monetaryUnit) {
        AdminConfig config = lambdaQuery().eq(AdminConfig::getName, "monetaryUnit").one();
        List<MonetaryUnitBO> monetaryUnitBOS = new ArrayList<>();
        List<OperationLog> operationLogList = new ArrayList<>();
        if (ObjectUtil.isNull(config)) {
            MonetaryUnitBO monetaryUnitBO = new MonetaryUnitBO();
            monetaryUnitBO.setUnit(0);
            monetaryUnitBO.setLabel(1);
            monetaryUnitBOS.add(monetaryUnitBO);

            AdminConfig adminConfig = new AdminConfig();
            adminConfig.setName("monetaryUnit");
            adminConfig.setValue(JSONUtil.toJsonStr(monetaryUnit));
            save(adminConfig);
        } else {
            monetaryUnitBOS = JSONUtil.toList(JSONUtil.parseArray(config.getValue()), MonetaryUnitBO.class);
            lambdaUpdate().eq(AdminConfig::getName, "monetaryUnit").set(AdminConfig::getValue, JSONUtil.toJsonStr(monetaryUnit)).update();
            BaseUtil.getRedis().del( "_monetaryUnit");
        }

        monetaryUnitBOS.forEach(monetaryUnitBO -> monetaryUnit.forEach(monetaryUnitBO1 -> {
            if (monetaryUnitBO.getLabel().equals(monetaryUnitBO1.getLabel())) {
                if (!monetaryUnitBO.getLabel().equals(1)) {
                    return;
                }
                OperationLog operationLog = new OperationLog();
                operationLog.setOperationObject(monetaryUnitBO.getLabelName());
                if (!monetaryUnitBO.getUnit().equals(monetaryUnitBO1.getUnit())) {
                    operationLog.setOperationInfo("将金额单位由：" + monetaryUnitBO.getUnitName() + "修改为：" + monetaryUnitBO1.getUnitName());
                }
                operationLogList.add(operationLog);
            }
        }));

        return operationLogList;
    }

    @Override
    public List<SimpleCrmEntity> querySimpleEntity(List<Object> ids) {
        if (ids.size() == 0) {
            return new ArrayList<>();
        }
        List<AdminConfig> list = lambdaQuery().select(AdminConfig::getSettingId, AdminConfig::getDescription).in(AdminConfig::getSettingId, ids).list();
        return list.stream().map(x -> {
            SimpleCrmEntity simpleCrmEntity = new SimpleCrmEntity();
            simpleCrmEntity.setId(x.getSettingId());
            simpleCrmEntity.setName(x.getDescription());
            return simpleCrmEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public BasePage<AdminConfig> queryModulePageList(PageEntity search) {
        return lambdaQuery().in(AdminConfig::getName, (Object[]) getValues()).page(search.parse());
    }

    private static final String INIT_AUTH_URL = "/adminConfig/moduleInitData";


    /**
     * 验证非管理员有无权限
     *
     * @param
     * @return boolean
     * @date 2020/11/23 10:35
     **/
    private boolean verifyInitAuth() {
        boolean isNoAuth = false;
        Long userId = UserUtil.getUserId();
        String key = userId.toString();
        List<String> noAuthMenuUrls = BaseUtil.getRedis().get(key);
        if (noAuthMenuUrls != null && noAuthMenuUrls.contains(INIT_AUTH_URL)) {
            isNoAuth = true;
        }
        return isNoAuth;
    }
    /**
     * 设置日志欢迎语
     *
     * @param stringList data
     */
    @Override
    public void setLogWelcomeSpeech(List<String> stringList) {

        List<AdminConfig> configList = new ArrayList<>();
        stringList.forEach(str -> {
            AdminConfig config = new AdminConfig();
            config.setName(LOG_CONFIG_NAME);
            config.setValue(str);
            config.setStatus(1);
            configList.add(config);
        });
        QueryWrapper<AdminConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", LOG_CONFIG_NAME);
        remove(queryWrapper);
        saveBatch(configList, Const.BATCH_SAVE_SIZE);
    }

    /**
     * 查询日志欢迎语
     *
     * @return data
     */
    @Override
    public List<LogWelcomeSpeechBO> getLogWelcomeSpeechList() {
        List<AdminConfig> adminConfigList = query().select("setting_id", "value").eq("name", LOG_CONFIG_NAME).list();
        return adminConfigList.stream().map(adminConfig -> BeanUtil.copyProperties(adminConfig, LogWelcomeSpeechBO.class)).collect(Collectors.toList());
    }
}
